from vtkmodules.vtkRenderingCore import vtkHardwareSelector

from CloudEngine.core.VTActor import VTActor
from CloudEngine.core.OutlineActor import OutLineActor
import vtkmodules.all as vtk
from CloudEngine.Math.Vector3 import Vector3

selectedColor = [0, 255, 0, 255]
unselectedColor = [255, 255, 0, 255]


class Selector:
    currentSelectedFaceId = -1

    hardwareSelector = None
    _cell_mode = vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS
    _point_mode = vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS

    def __init__(self, app):
        self.propPicker = vtk.vtkPropPicker()
        self.parent = app
        # 单元选择器
        self.cellPicker = vtk.vtkCellPicker()
        # 点选择器
        self.pointPicker = vtk.vtkPointPicker()
        # 基于硬件的选择器
        self.hardwareSelector = vtk.vtkOpenGLHardwareSelector()
        self.cellPickList: list[VTActor] = []
        self.LinePickList: list[OutLineActor] = []
        self.pointPickList = []
        self.currentSelectedFaceIds = set()
        self.currentSelectedActors = []
        self.maskFaceIds = set()
        self.cellPicker.SetPickFromList(1)
        self.cellPicker.InitializePickList()

    def AddToTargetList(self, actor):
        if actor.instance not in self.cellPicker.GetPickList():
            self.cellPicker.AddPickList(actor.instance)
            self.cellPickList.append(actor)

    def AddToPointTargetList(self, actor):
        if actor.instance not in self.pointPicker.GetPickList():
            self.cellPicker.AddPickList(actor.instance)
            self.pointPickList.append(actor)

    def setLineTargetList(self, actor: OutLineActor):
        if actor.instance not in self.cellPicker.GetPickList():
            self.cellPicker.AddPickList(actor.instance)
            self.LinePickList.append(actor)

    def pickVertexPoint(self, point, threshold=2):
        if len(self.pointPickList) == 0:
            return
        pointsArr = self.pointPickList[0].GetPoints()
        pickedPoints = self.pointPicker.GetPickedPositions()
        if len(pickedPoints) == 0:
            return

        pickedPoint = pickedPoints[0]
        for i in range(len(pointsArr)):
            point = pointsArr.GetPoint(i)
            if (
                abs(point[0] - pickedPoint[0]) < threshold
                and abs(point[1] - pickedPoint[1]) < threshold
                and abs(point[2] - pickedPoint[2]) < threshold
            ):
                return {"id": pointsArr[i].id, "XYZ": pointsArr[i].XYZ}

    def getPickedVTActors(self):
        vtInstanceArr = self.cellPicker.GetActors()
        result = []
        vtInstanceArr.InitTraversal()
        nextActor = vtInstanceArr.GetNextActor()

        while nextActor:
            for i in range(len(self.cellPickList)):
                if nextActor == self.cellPickList[i].instance:
                    result.append(self.cellPickList[i])
                    break
            nextActor = vtInstanceArr.GetNextActor()
        return result

    def pickCell(self, x, y) -> int:
        """
        根据给定的坐标(x, y)选择一个单元格，并返回该单元格的ID。

        参数:
        x (int): 横坐标
        y (int): 纵坐标

        返回:
        int: 单元格的ID
        """
        self.cellPicker.Pick(x, y, 0, self.parent.renderer)
        return self.cellPicker.GetCellId()

    def select(self, x, y):
        self.cellPicker.Pick(x, y, 0, self.parent.renderer)

        picked_line = self.selectByPoint()
        if picked_line is None:
            self.selectByCell()

    def selectByPoint(self):
        picked_position = self.cellPicker.GetPickPosition()
        print(picked_position, "world_position")
        picker_point = Vector3(
            picked_position[0], picked_position[1], picked_position[2]
        )
        picked_line = None
        outline = None
        if picked_position is None:
            return
        for outLine in self.LinePickList:
            for line in outLine.virtualLines:
                distance = line.distanceFromPoint(picker_point)
                if distance <= self.cellPicker.GetTolerance():
                    print(distance, "distance")
                    picked_line = line
                    outline = outLine

        if picked_line is None:
            return None
        if picked_line in self.currentSelectedActors:
            self.unselectedLine(outline, picked_line.id)
            self.currentSelectedActors.remove(picked_line)
        else:
            self.selectLine(outline, picked_line.id)
            self.currentSelectedActors.append(picked_line)

        return picked_line

    def selectByCell(
        self,
    ):
        cell_id = self.cellPicker.GetCellId()

        if cell_id == -1:
            return
        actors = self.getPickedVTActors()
        if len(actors) == 0:
            return
        for actor in actors:
            vt_actor, actor_type = self.find_actor_info(actor)
            if actor in self.currentSelectedActors:
                return self.unselected(actor, cell_id, vt_actor, actor_type)
            if actor_type == "surface":
                self.selectFace(vt_actor, cell_id)
            elif actor_type == "line":
                self.selectLine(vt_actor, cell_id)
            self.parent.StateMachine.select(actor)
            self.currentSelectedActors.append(actor)
        self.parent.d_render()
        self.parent.export_image()

    def selectFace(self, vt_actor, cell_id):
        print(vt_actor, "vt_actor")
        vt_actor.create_cell_color(cell_id=cell_id, color=selectedColor)

    def selectLine(self, vt_actor, cell_id):
        vt_actor.create_cell_color(color=selectedColor, cell_id=cell_id)

    def unselected(self, actor, cell_id, vt_actor, actor_type):
        if actor is None:
            return

        for actor in self.currentSelectedActors:
            if actor_type == "surface":
                self.unselectedFace(vt_actor, cell_id)
            elif actor_type == "line":
                self.unselectedLine(vt_actor, cell_id)
        self.currentSelectedActors.remove(actor)

        self.parent.d_render()

    def unselectedFace(self, vt_actor, cell_id):
        vt_actor.create_cell_color(cell_id=cell_id, color=unselectedColor)

    def unselectedLine(self, vt_actor, cell_id):
        vt_actor.create_cell_color(cell_id=cell_id, color=unselectedColor)

    def find_actor_info(self, actor):
        vt_actor = None
        actor_type = "surface"
        for i in range(len(self.cellPickList)):
            if actor == self.cellPickList[i].instance:
                vt_actor = self.cellPickList[i]
                actor_type = "surface"
                return vt_actor, actor_type
        for i in range(len(self.LinePickList)):
            if actor == self.LinePickList[i].instance:
                vt_actor = self.LinePickList[i]
                actor_type = "line"
                return vt_actor, actor_type
        for i in range(len(self.pointPickList)):
            if actor == self.pointPickList[i].instance:
                vt_actor = self.pointPickList[i]
                actor_type = "point"
                return vt_actor, actor_type

    def pick_vertex_point(self, point: [float], partId: int, threshold=2):
        if len(self.pointPickList) == 0:
            return None
        points_arr = []
        for item in self.pointPickList:
            if item.partId == partId:
                points_arr = self.pointPickList
        self.pointPicker.Pick(point, self.parent.renderer)
        picked_points = self.pointPicker.GetPickedPositions()
        if len(picked_points) == 0:
            return None
        picked_point = picked_points[0]
        b = Vector3(picked_point[0], picked_point[1], picked_point[2])
        # 根据选中的点的坐标，和已有的坐标进行距离计算，然后找到最靠近的点
        for item in points_arr:
            xyz = item.get("XYZ")
            a = Vector3(item.x, item.y, item.z)
            if a.distance_to(b) < threshold:
                return {
                    "id": item.get("id"),
                    "XYZ": item.get("XYZ"),
                }
        return None
